package com.danan.realtime.util;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.flink.shaded.guava18.com.google.common.base.CaseFormat;
import redis.clients.jedis.Jedis;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author NanHuang
 * @Date 2023/1/24
 */
public class JDBCUtil {

    private static DruidDataSource phoenixDataSource;
    private static DruidDataSource mysqlDataSource;

    static {
        // Phoenix
        // 创建连接池
        phoenixDataSource = new DruidDataSource();
        // 设置驱动全类名
        phoenixDataSource.setDriverClassName(ResourceBundleUtil.getProperty("phoenix.driver"));
        // 设置连接 url
        phoenixDataSource.setUrl(ResourceBundleUtil.getProperty("phoenix.url"));
        // 设置初始化连接池时池中连接的数量
        phoenixDataSource.setInitialSize(5);
        // 设置同时活跃的最大连接数
        phoenixDataSource.setMaxActive(100);
        // 设置空闲时的最小连接数，必须介于 0 和最大连接数之间，默认为 0
        phoenixDataSource.setMinIdle(10);
        // 设置没有空余连接时的等待时间，超时抛出异常，-1 表示一直等待
        phoenixDataSource.setMaxWait(-1);
        // 验证连接是否可用使用的 SQL 语句
        phoenixDataSource.setValidationQuery("select 1");
        // 指明连接是否被空闲连接回收器（如果有）进行检验，如果检测失败，则连接将被从池中去除
        // 注意，默认值为 true，如果没有设置 validationQuery，则报错
        // testWhileIdle is true, validationQuery not set
        phoenixDataSource.setTestWhileIdle(true);
        // 借出连接时，是否测试，设置为 true，不测试可能连接无法使用
        phoenixDataSource.setTestOnBorrow(true);
        // 归还连接时，是否测试
        phoenixDataSource.setTestOnReturn(false);
        // 设置空闲连接回收器每隔 30s 运行一次
        phoenixDataSource.setTimeBetweenEvictionRunsMillis(30 * 1000L);
        // 设置池中连接空闲 30min 被回收，默认值即为 30 min
        phoenixDataSource.setMinEvictableIdleTimeMillis(30 * 60 * 1000L);

        // MySQL
        // 创建连接池
        mysqlDataSource = new DruidDataSource();
        // 设置驱动全类名
        mysqlDataSource.setDriverClassName(ResourceBundleUtil.getProperty("mysql.driver"));
        // 设置连接 url
        mysqlDataSource.setUrl("jdbc:mysql://hadoop102:3306/gmall_config?useSSL=false");
        // 设置用户名
        mysqlDataSource.setUsername(ResourceBundleUtil.getProperty("mysql.username"));
        // 设置密码
        mysqlDataSource.setPassword(ResourceBundleUtil.getProperty("mysql.password"));
        // 设置初始化连接池时池中连接的数量
        mysqlDataSource.setInitialSize(5);
        // 设置同时活跃的最大连接数
        mysqlDataSource.setMaxActive(100);
        // 设置空闲时的最小连接数，必须介于 0 和最大连接数之间，默认为 0
        mysqlDataSource.setMinIdle(10);
        // 设置没有空余连接时的等待时间，超时抛出异常，-1 表示一直等待
        mysqlDataSource.setMaxWait(-1);
        // 验证连接是否可用使用的 SQL 语句
        mysqlDataSource.setValidationQuery("select 1");
        // 指明连接是否被空闲连接回收器（如果有）进行检验，如果检测失败，则连接将被从池中去除
        // 注意，默认值为 true，如果没有设置 validationQuery，则报错
        // testWhileIdle is true, validationQuery not set
        mysqlDataSource.setTestWhileIdle(true);
        // 借出连接时，是否测试，设置为 true，不测试可能连接无法使用
        mysqlDataSource.setTestOnBorrow(true);
        // 归还连接时，是否测试
        mysqlDataSource.setTestOnReturn(false);
        // 设置空闲连接回收器每隔 30s 运行一次
        mysqlDataSource.setTimeBetweenEvictionRunsMillis(30 * 1000L);
        // 设置池中连接空闲 30min 被回收，默认值即为 30 min
        mysqlDataSource.setMinEvictableIdleTimeMillis(30 * 60 * 1000L);
    }

    public static Connection getPhoenixConnection() throws SQLException {
        return phoenixDataSource.getConnection();
    }
    public static Connection getMySQLConnection() throws SQLException {
        return mysqlDataSource.getConnection();
    }


    public static <T> List<T> queryList(Connection conn, String sql, Class<T> clazz, boolean isUnderLineToCamel, String... params) throws Exception {
        // 1 预编译SQL
        PreparedStatement ps = conn.prepareStatement(sql);
        // 2 占位符赋值
        if (params.length != 0) {
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1,params[i]);
            }
        }
        // 3 执行查询，获取查询结果的元数据
        ResultSet resultSet = ps.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        // 4 创建JavaBean对象，根据查询结果进行赋值
        ArrayList<T> result = new ArrayList<>();
        while (resultSet.next()){
            // 利用反射创建对象
            T t = clazz.newInstance();
            // 查询每个字段的值
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                // 获取第i列字段名称
                String columnName = metaData.getColumnName(i);
                // 下划线 - > 驼峰
                if (isUnderLineToCamel) {
                    columnName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,columnName);
                }
                // 获取第i列字段属性
                Object value = resultSet.getObject(i);
                // 给对象属性赋值
                BeanUtils.setProperty(t,columnName,value);
            }
            result.add(t);
        }
        return result;
    }

    public static JSONObject getDimInfoFromPhoenix(Connection conn, String table, String id) throws Exception {
        // 1 拼接sql
        String sql = "select * from " + table + " where id = '" + id + "'";
        // 2 查询结果
        return queryList(conn,sql, JSONObject.class,false).iterator().next();
    }

    public static JSONObject getDimInfoFromPhoenix(Jedis jedis, Connection conn, String table, String id) throws Exception {
        String key = table + ":" + id;
        // 1 先查询Redis中是否有缓存
        String cacheStr = jedis.get(key);
        if (cacheStr != null) {
//            System.out.println(" -- Redis --");
            return JSON.parseObject(cacheStr);
        } else {
            // 1 拼接sql
            String sql = "select * from " + table + " where id = '" + id + "'";
            // 2 查询结果
            JSONObject result = queryList(conn, sql, JSONObject.class, false).iterator().next();
            // 3 存入Redis
            jedis.setex(key,2 * 24 * 60 * 60,result.toJSONString());//设置缓存的TTL
            // 4 返回结果
//            System.out.println(" -- Phoenix --");
            return result;
        }
    }
}
